#include "bsp_i2c.h"
#include "gd32a508_gpio.h"
#include "systick.h"

#define IIC_I_PORT_RCU RCU_GPIOB
#define IIC_I_SCL_PORT GPIOB
#define IIC_I_SCL_PIN GPIO_PIN_6
#define IIC_I_SDA_PORT GPIOB
#define IIC_I_SDA_PIN GPIO_PIN_7

// eep : PA8->SCL PC9->SDA
// ads1: PD1->SCL PD0->SDA
// ads2: PD3->SCL PD2->SDA
// ads3: PD5->SCL PD4->SDA
// ads4: PD7->SCL PD6->SDA

#define mHIGH true
#define mLOW  false

dv_I2C_TypeDef dv_I2C;

static uint32_t iic_SCLport[5] = {GPIOA, GPIOD, GPIOD, GPIOD, GPIOD};
static uint32_t iic_SDAport[5] = {GPIOC, GPIOD, GPIOD, GPIOD, GPIOD};

static uint32_t iic_SCLpin[5] = {GPIO_PIN_8, GPIO_PIN_7, GPIO_PIN_5, GPIO_PIN_3, GPIO_PIN_1};
static uint32_t iic_SDApin[5] = {GPIO_PIN_9, GPIO_PIN_6, GPIO_PIN_4, GPIO_PIN_2, GPIO_PIN_0};

static rcu_periph_enum iic_SCL_RCU[5]  = {RCU_GPIOA, RCU_GPIOD, RCU_GPIOD, RCU_GPIOD, RCU_GPIOD};
static rcu_periph_enum iic_SDA_RCU[5]  = {RCU_GPIOC, RCU_GPIOD, RCU_GPIOD, RCU_GPIOD, RCU_GPIOD};

static void SDA_PORT_IN(I2C_PORT iicx)
{
    gpio_init(iic_SDAport[iicx],GPIO_MODE_IN_FLOATING,GPIO_OSPEED_MAX,iic_SDApin[iicx]);
}

static uint32_t *addrTemp;
static void SDA_PORT_OUT(I2C_PORT iicx)
{
    gpio_init(iic_SDAport[iicx],GPIO_MODE_OUT_OD,GPIO_OSPEED_MAX,iic_SDApin[iicx]);
}

static void SET_SCL_LEVEL(I2C_PORT iicx, bool level)
{
    FlagStatus opt;

    if (mLOW == level)
    {
        opt = RESET;
    }
    else
    {
        opt = SET;
    }
    gpio_bit_write(iic_SCLport[iicx], iic_SCLpin[iicx], opt);
}

static void SET_SDA_LEVEL(I2C_PORT iicx, bool level)
{
    FlagStatus opt;

    if (mLOW == level)
    {
        opt = RESET;
    }
    else
    {
        opt = SET;
    }
    gpio_bit_write(iic_SDAport[iicx], iic_SDApin[iicx], opt);
}

static unsigned char GET_SDA_LEVEL(I2C_PORT iicx)
{
    return gpio_input_bit_get(iic_SDAport[iicx], iic_SDApin[iicx]);
}


static void GPIO_I2C_Init(I2C_PORT iicx)
{    
    rcu_periph_clock_enable(iic_SCL_RCU[iicx]);
    rcu_periph_clock_enable(iic_SDA_RCU[iicx]);

    /*!< Configure sEE_I2C pins: SCL*/
    gpio_init(iic_SCLport[iicx], GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, iic_SCLpin[iicx]);

    /*!< Configure sEE_I2C pins: SDA */
    gpio_init(iic_SDAport[iicx], GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, iic_SDApin[iicx]);
}


// 产生IIC起始信号
static void IIC_Start(I2C_PORT iicx)
{
    SDA_PORT_OUT(iicx); // sda线输出
    SET_SDA_LEVEL(iicx, mHIGH);
    SET_SCL_LEVEL(iicx, mHIGH);
    Delay_us(2);
    SET_SDA_LEVEL(iicx, mLOW); // START:when CLK is high,DATA change form high to low
    Delay_us(1);
    SET_SCL_LEVEL(iicx, mLOW); // 钳住I2C总线，准备发送或接收数据
}

// 产生IIC停止信号
static void IIC_Stop(I2C_PORT iicx)
{
    SDA_PORT_OUT(iicx); // sda线输出
    SET_SCL_LEVEL(iicx, mLOW);
    SET_SDA_LEVEL(iicx, mLOW); // STOP:when CLK is high DATA change form low to high
    Delay_us(2);
    SET_SCL_LEVEL(iicx, mHIGH);
    SET_SDA_LEVEL(iicx, mHIGH); // 发送I2C总线结束信号
    Delay_us(1);
}

static unsigned char IIC_Wait_Ack(I2C_PORT iicx)
{
    uint8_t ucErrTime = 0;
    SDA_PORT_IN(iicx); // SDA设置为输入
    SET_SCL_LEVEL(iicx, mHIGH);
    Delay_us(1);
    while (GET_SDA_LEVEL(iicx))
    {
        ucErrTime++;
        if (ucErrTime > 250)
        {
            IIC_Stop(iicx);
            return 1;
        }
    }
    SET_SCL_LEVEL(iicx, mLOW); // 时钟输出0
    Delay_us(2);
    return 0;
}

static void IIC_Ack(I2C_PORT iicx)
{
    SET_SCL_LEVEL(iicx, mLOW);
    SDA_PORT_OUT(iicx);
    SET_SDA_LEVEL(iicx, mLOW);
    Delay_us(1);
    SET_SCL_LEVEL(iicx, mHIGH);
    Delay_us(1);
    SET_SCL_LEVEL(iicx, mLOW);
}

static void IIC_NAck(I2C_PORT iicx)
{
    SET_SCL_LEVEL(iicx, mLOW);
    SDA_PORT_OUT(iicx);
    SET_SDA_LEVEL(iicx, mHIGH);
    Delay_us(1);
    SET_SCL_LEVEL(iicx, mHIGH);
    Delay_us(1);
    SET_SCL_LEVEL(iicx, mLOW);
}


static void IIC_Send_Byte(I2C_PORT iicx,unsigned char data)
{
    unsigned char t;

    SDA_PORT_OUT(iicx);
    SET_SCL_LEVEL(iicx, mLOW); // 拉低时钟开始数据传输
    for (t = 0; t < 8; t++)
    {
        if (((data & 0x80) >> 7))
        {
            SET_SDA_LEVEL(iicx, mHIGH);
        }
        else
        {
            SET_SDA_LEVEL(iicx, mLOW);
        }
        // IIC_SDA=(txd&0x80)>>7;
        data <<= 1;
        Delay_us(1); // 对TEA5767这三个延时都是必须的
        SET_SCL_LEVEL(iicx, mHIGH);
        Delay_us(1);
        SET_SCL_LEVEL(iicx, mLOW);
        Delay_us(1);
    }
}

static unsigned char IIC_Read_Byte(I2C_PORT iicx,unsigned char ack)
{
    unsigned char i, receive = 0;
    SDA_PORT_IN(iicx); // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        SET_SCL_LEVEL(iicx, mLOW);
        Delay_us(1);
        SET_SCL_LEVEL(iicx, mHIGH);
        receive <<= 1;
        if (GET_SDA_LEVEL(iicx))
        {
            receive++;
        }
        Delay_us(1);
    }
    if (!ack)
    {
        IIC_NAck(iicx); // 发送nACK
    }
    else
    {
        IIC_Ack(iicx); // 发送ACK
    }
    return receive;
}

static uint8_t bsp_eep_i2c_write_buffer(I2C_PORT iicx, uint8_t SlvAddr,
                                    uint16_t Addr, uint8_t *pData, uint16_t Num)
{
    IIC_Start(iicx);
    IIC_Send_Byte(iicx,SlvAddr);  // 发送写命令
    IIC_Wait_Ack(iicx);
    IIC_Send_Byte(iicx,(uint8_t)Addr);  // 发送低地址
    IIC_Wait_Ack(iicx);

    while (Num--)
    {
        IIC_Send_Byte(iicx,*pData++); // 发送字节
        IIC_Wait_Ack(iicx);
    }

    IIC_Stop(iicx); // 产生一个停止条件
    delay_1ms(6);
    return true;
}

static uint8_t bsp_eep_i2c_read_buffer(I2C_PORT iicx, uint8_t SlvAddr,
                                   uint16_t Addr, uint8_t *pData, uint16_t Num)
{
    IIC_Start(iicx);
    IIC_Send_Byte(iicx,SlvAddr & 0xFE);  // 发送器件地址,写数据
    IIC_Wait_Ack(iicx);

    IIC_Send_Byte(iicx,(uint8_t)Addr);  // 发送低地址
    IIC_Wait_Ack(iicx);

    IIC_Start(iicx);
    IIC_Send_Byte(iicx,SlvAddr | 0x01);  // 进入接收模式
    IIC_Wait_Ack(iicx);

    while (--Num)
    {
        *pData = IIC_Read_Byte(iicx,1);
        pData++;
    }
    *pData = IIC_Read_Byte(iicx,0);
    IIC_Stop(iicx);  // 产生一个停止条件

    return true;
}

static uint8_t bsp_ads1110_i2c_write_buffer(I2C_PORT iicx, uint8_t SlvAddr,uint8_t *pData, uint16_t Num)
{
    IIC_Start(iicx);
    IIC_Send_Byte(iicx,SlvAddr& 0xFE);  // 发送写命令
    IIC_Wait_Ack(iicx);

    while (Num--)
    {
        IIC_Send_Byte(iicx,*pData++); // 发送字节
        IIC_Wait_Ack(iicx);
    }

    IIC_Stop(iicx); // 产生一个停止条件
    delay_1ms(6);
    return true;
}

static uint8_t bsp_ads1110_i2c_read_buffer(I2C_PORT iicx, uint8_t SlvAddr,uint8_t *pData, uint16_t Num)
{
    IIC_Start(iicx);
    IIC_Send_Byte(iicx,SlvAddr | 0x01);  // 进入接收模式
    IIC_Wait_Ack(iicx);

    while (--Num)
    {
        *pData = IIC_Read_Byte(iicx,1);
        pData++;
    }
    *pData = IIC_Read_Byte(iicx,0);
    IIC_Stop(iicx);  // 产生一个停止条件

    return true;
}


void init_dv_I2C(void)
{
    dv_I2C.finit     = GPIO_I2C_Init;;
    dv_I2C.feepRead  = bsp_eep_i2c_read_buffer;
    dv_I2C.feepWrite = bsp_eep_i2c_write_buffer;
    dv_I2C.fadsRead  = bsp_ads1110_i2c_read_buffer;
    dv_I2C.fadsWrite = bsp_ads1110_i2c_write_buffer;
}
